package com.tianji.learning.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.api.client.course.CourseClient;
import com.tianji.api.dto.course.CourseFullInfoDTO;
import com.tianji.api.dto.leanring.LearningLessonDTO;
import com.tianji.api.dto.leanring.LearningRecordDTO;
import com.tianji.common.exceptions.BizIllegalException;
import com.tianji.common.exceptions.DbException;
import com.tianji.common.utils.BeanUtils;
import com.tianji.common.utils.UserContext;
import com.tianji.learning.domain.dto.LearningRecordFormDTO;
import com.tianji.learning.domain.po.LearningLesson;
import com.tianji.learning.domain.po.LearningRecord;
import com.tianji.learning.enums.LessonStatus;
import com.tianji.learning.enums.SectionType;
import com.tianji.learning.mapper.LearningRecordMapper;
import com.tianji.learning.service.ILearningLessonService;
import com.tianji.learning.service.ILearningRecordService;
import com.tianji.learning.utils.LearningRecordDelayTaskHandler;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 学习记录表 服务实现类
 * </p>
 *
 * @author snow
 * @since 2023-10-21
 */
@Service
@RequiredArgsConstructor
public class LearningRecordServiceImpl extends ServiceImpl<LearningRecordMapper, LearningRecord> implements ILearningRecordService {
    private final ILearningLessonService lessonService;
    private final CourseClient courseClient;
    private final LearningRecordDelayTaskHandler taskHandler;

    /**
     * 查询用户指定课程学习进度
     *
     * @param courseId
     * @return
     */
    @Override
    public LearningLessonDTO queryLearningRecordByCourse(Long courseId) {

        //获取当前用户id
        Long userId = UserContext.getUser();
        //查询课表信息 条件 user_id 和course_id
        LearningLesson learningLesson = lessonService.lambdaQuery()
                .eq(LearningLesson::getUserId, userId)
                .eq(LearningLesson::getCourseId, courseId)
                .one();
        if (learningLesson == null) {
            throw new BizIllegalException("该课程未加入课表");
        }
        //查询学习记录 条件 lesson_id 和 userId
        List<LearningRecord> learningRecordList = this.lambdaQuery()
                .eq(LearningRecord::getLessonId, learningLesson.getId())
                .eq(LearningRecord::getUserId, userId)
                .list();
        if (learningRecordList == null && learningRecordList.size() == 0) {
            return null;
        }
        //封装结果返回
        LearningLessonDTO learningLessonDTO = new LearningLessonDTO();
        learningLessonDTO.setLatestSectionId(learningLesson.getLatestSectionId());
        learningLessonDTO.setId(learningLesson.getId());
        List<LearningRecordDTO> dtoList = BeanUtils.copyList(learningRecordList, LearningRecordDTO.class);
        learningLessonDTO.setRecords(dtoList);
        return learningLessonDTO;
    }

    /**
     * 提交学习记录
     *
     * @param learningRecordFormDTO
     */
    @Override
    public void addLearningRecord(LearningRecordFormDTO learningRecordFormDTO) {
        //获取当前登录用户id
        Long userId = UserContext.getUser();
        //处理学习记录
        //判断是视频或考试
        boolean isFinished = false; //代表本小节是否已学完
        if (learningRecordFormDTO.getSectionType().equals(SectionType.VIDEO)) {
            //提交视频播放记录
            isFinished = handleVideoRecod(userId, learningRecordFormDTO);
        } else {
            //提交考试记录
            isFinished = handleExamRecord(userId, learningRecordFormDTO);
        }
        //处理课表数据
        if (!isFinished){
            return;
        }
        handleLessonData(learningRecordFormDTO, isFinished);
    }

    /**
     * 处理课表数据
     *
     * @param learningRecordFormDTO
     * @param isFinished
     */
    private void handleLessonData(LearningRecordFormDTO learningRecordFormDTO, boolean isFinished) {
        //查询课表数据 learning_lesson 条件 lesson_id
        LearningLesson learningLesson = lessonService.getById(learningRecordFormDTO.getLessonId());
        if (learningLesson == null) {
            throw new BizIllegalException("课表不存在");
        }
        //判断是否是第一次学完
        boolean allFinished = false;
        if (isFinished) {

            //远程调用课程服务得到课程信息
            CourseFullInfoDTO cinfo = courseClient.getCourseInfoById(learningLesson.getCourseId(), false, false);
            if (cinfo == null) {
                throw new BizIllegalException("课程不存在");
            }
            //判断该用户对该课程下全部小结是否学完
            Integer sectionNum = cinfo.getSectionNum();//该课程下小节的总数
            Integer learnedSections = learningLesson.getLearnedSections();//当前用户对课程已学的小节数
            allFinished = learnedSections + 1 >= sectionNum;
        }
        //更新课表数据
        lessonService.lambdaUpdate()
//                .set(learningLesson.getStatus() == LessonStatus.NOT_BEGIN.getValue() , LearningLesson::getStatus , LessonStatus.LEARNING)
                .set(learningLesson.getLearnedSections() == 0, LearningLesson::getStatus, LessonStatus.LEARNING.getValue())
                .set(allFinished, LearningLesson::getStatus, LessonStatus.FINISHED)
                .set(LearningLesson::getLatestSectionId, learningRecordFormDTO.getSectionId())
                .set(LearningLesson::getLatestLearnTime, learningRecordFormDTO.getCommitTime())
//                .set(isFinished,LearningLesson::getLearnedSections,learningLesson.getLearnedSections()+1)
                .setSql(isFinished, "learned_sections = learned_sections + 1")
                .eq(LearningLesson::getId, learningLesson.getId())
                .update();
    }

    /**
     * 处理视频记录
     *
     * @param userId
     * @param learningRecordFormDTO
     * @return
     */
    private boolean handleVideoRecod(Long userId, LearningRecordFormDTO learningRecordFormDTO) {
        //查询旧的学习记录表 条件 userId lessonId section_id
        LearningRecord learningRecord = queryOldRecord(learningRecordFormDTO.getLessonId(), learningRecordFormDTO.getSectionId());
        //判断是否存在
        if (learningRecord == null) {
            //如果不存在则新增学习记录
            LearningRecord record = BeanUtils.copyBean(learningRecordFormDTO, LearningRecord.class);
            record.setUserId(userId);
            //保存学习记录
            this.save(record);
            return false;
        } else {
            //如果存在则更新学习记录
            //判断是否已完成
            boolean isFinished = !learningRecord.getFinished() && (learningRecordFormDTO.getMoment() * 2 >= learningRecordFormDTO.getDuration());
            //为true表示第一次完成
            if (!isFinished){
                LearningRecord record = new LearningRecord();
                record.setLessonId(learningRecordFormDTO.getLessonId());
                record.setSectionId(learningRecordFormDTO.getSectionId());
                record.setId(learningRecord.getId());
                record.setFinished(learningRecord.getFinished());
                record.setMoment(learningRecordFormDTO.getMoment());
                taskHandler.addLearningRecordTask(record);
                return false;
            }
            boolean update = this.lambdaUpdate()
                    .set(LearningRecord::getMoment, learningRecordFormDTO.getMoment())
                    .set(isFinished, LearningRecord::getFinished, true)
                    .set(isFinished, LearningRecord::getFinishTime, learningRecordFormDTO.getCommitTime())
                    .eq(LearningRecord::getId, learningRecord.getId())
                    .update();
            if (!update) {
                throw new DbException("更新视频学习记录失败");
            }
            return isFinished;
        }

    }

    private LearningRecord queryOldRecord(Long lessonId, Long sectionId) {
//        查询缓存
        LearningRecord cache = taskHandler.readRecordCache(lessonId, sectionId);
//        如果命中直接返回
        if (cache != null) {
            return cache;
        }
//        如果未命中则查询DB
        LearningRecord dbRecord = this.lambdaQuery()
                .eq(LearningRecord::getLessonId, lessonId)
                .eq(LearningRecord::getSectionId, sectionId)
                .one();
//        将DB查出来的数据放入缓存
        if (dbRecord == null) {
            return null;
        }
        taskHandler.writeRecordCache(dbRecord);
        return dbRecord;
    }

    /**
     * 处理考试记录
     *
     * @param userId
     * @param learningRecordFormDTO
     * @return
     */
    private boolean handleExamRecord(Long userId, LearningRecordFormDTO learningRecordFormDTO) {
        //保存学习记录
        //将dto转换为vo
        LearningRecord learningRecord = BeanUtils.copyBean(learningRecordFormDTO, LearningRecord.class);
        learningRecord.setUserId(userId);
        learningRecord.setFinished(true);//提交考试记录 代表本小节已学完
        learningRecord.setFinishTime(LocalDateTime.now());

        boolean save = this.save(learningRecord);
        if (!save) {
            throw new DbException("新增考试记录失败失败");
        }
        return save;
    }
}
